home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / daten / astrolog / src / io.c < prev    next >
C/C++ Source or Header  |  1995-08-11  |  23KB  |  830 lines

  1. /*                                                               -*- C -*-
  2. ** Astrolog (Version 4.40) File: io.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1995 by Walter D. Pullen
  6. ** (astara@u.washington.edu). Permission is granted to freely use and
  7. ** distribute these routines provided one doesn't sell, restrict, or
  8. ** profit from them in any way. Modification is allowed provided these
  9. ** notices remain with any altered or edited versions of the program.
  10. **
  11. ** The main planetary calculation routines used in this program have
  12. ** been Copyrighted and the core of this program is basically a
  13. ** conversion to C of the routines created by James Neely as listed in
  14. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  15. ** available from Matrix Software. The copyright gives us permission to
  16. ** use the routines for personal use but not to sell them or profit from
  17. ** them in any way.
  18. **
  19. ** The PostScript code within the core graphics routines are programmed
  20. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  21. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  22. **
  23. ** The extended accurate ephemeris databases and formulas are from the
  24. ** calculation routines in the program "Placalc" and are programmed and
  25. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  26. ** (alois@azur.ch). The use of that source code is subject to
  27. ** regulations made by Astrodienst Zurich, and the code is not in the
  28. ** public domain. This copyright notice must not be changed or removed
  29. ** by any user of this program.
  30. **
  31. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  32. ** X Window graphics initially programmed 10/23-29/1991.
  33. ** PostScript graphics initially programmed 11/29-30/1992.
  34. ** Last code change made 1/29/1995.
  35. */
  36.  
  37. /* $VER: $Id: io.c,v 1.2 1995/07/02 22:21:54 tf Exp $ */
  38.  
  39. #include "astrolog.h"
  40.  
  41. /*
  42. ******************************************************************************
  43. ** File IO Routines.
  44. ******************************************************************************
  45. */
  46.  
  47. /* Open the file indicated by the given string and return the file's stream */
  48. /* pointer, or NULL if the file couldn't be found or opened. All parts of   */
  49. /* the program which open files to read call this routine. We look in       */
  50. /* several various locations and directories for the file before giving up. */
  51.  
  52. FILE *FileOpen(szFile, nFileMode)
  53. char *szFile;
  54. int nFileMode;
  55. {
  56.   FILE *file;
  57.   char name[cchSzDef], mode[3];
  58. #ifdef ENVIRON
  59.   char *env;
  60. #endif
  61.  
  62.   /* Some file types we want to open as binary instead of Ascii. */
  63.   sprintf(mode, "%s", (nFileMode == 2) ? "rb" : "r");
  64.  
  65.   /* First look for the file in the current directory. */
  66.   file = fopen(szFile, mode);
  67.   if (file != NULL)
  68.     return file;
  69.  
  70. #ifdef ENVIRON
  71.   /* Next look for the file in the directory indicated by the version */
  72.   /* specific system environment variable.                            */
  73.  
  74.   sprintf(name, "%s%s", ENVIRONVER, szVersionCore);
  75.   env = getenv(name);
  76.  
  77.   if (env && *env) 
  78.   {
  79.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  80.     file = fopen(name, mode);
  81.     if (file != NULL)
  82.       return file;
  83.   }
  84.  
  85.   /* Next look in the directory in the general environment variable. */
  86.  
  87.   env = getenv(ENVIRONALL);
  88.  
  89.   if (env && *env) 
  90.   {
  91.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  92.     file = fopen(name, mode);
  93.     if (file != NULL)
  94.       return file;
  95.   }
  96.  
  97.   /* Next look in the directory in the version prefix environment variable. */
  98.  
  99.   env = getenv(ENVIRONVER);
  100.  
  101.   if (env && *env)
  102.   {
  103.     sprintf(name, "%s%c%s", env, chDirSep, szFile);
  104.     file = fopen(name, mode);
  105.     if (file != NULL)
  106.       return file;
  107.   }
  108. #endif
  109.  
  110.   /* Finally look in one of several directories specified at compile time. */
  111.  
  112. #ifdef AMIGA
  113.   /* On Amiga systems the ':' is (as well as '/') a valid chDirSep */
  114.  
  115.   { char *s= (nFileMode == 0) ? DEFAULT_DIR : (nFileMode == 1 ? CHART_DIR : EPHE_DIR);
  116.     char c= s[ strlen(s)-1 ];
  117.  
  118.     if( c == chDirSep || c == ':' )
  119.       sprintf(name, "%s%s", s, szFile);
  120.  
  121.     else
  122.       sprintf(name, "%s%c%s", s, chDirSep, szFile);
  123.   }
  124.  
  125. #else /* !AMIGA */
  126.   sprintf(name, "%s%c%s", nFileMode == 0 ? DEFAULT_DIR : (nFileMode == 1 ? CHART_DIR : EPHE_DIR), chDirSep, szFile);
  127. #endif
  128.  
  129.   file = fopen(name, mode);
  130.  
  131.   if (file == NULL && nFileMode == 1)
  132.   {
  133.     /* If the file was never found, print an error (unless we were looking */
  134.     /* for a certain file type, e.g. the optional astrolog.dat file).      */
  135.  
  136.     sprintf(name, "File '%s' not found.", szFile);
  137.     PrintError(name);
  138.   }
  139.   return file;
  140. }
  141.  
  142. /* This is Astrolog's generic file processing routine, which handles chart */
  143. /* info files, position files, and config files. Given a file name or a    */
  144. /* file handle, run through each line as a series of command switches.     */
  145.  
  146. bool FProcessSwitchFile(szFile, file)
  147. char *szFile;
  148. FILE *file;
  149. {
  150.   char szLine[cchSzMax], *argv[MAXSWITCHES], ch;
  151.   int argc, i;
  152.  
  153.   if(!file)
  154.     file = FileOpen(szFile, 0);
  155.  
  156.   if(!file)
  157.     return fFalse;
  158.  
  159.   /* All files have to begin with the -@ switch file type identifier. */
  160.  
  161.   ch= getc(file); ungetc(ch, file);
  162.  
  163.   if(ch != '@')
  164.   {
  165.     sprintf(szLine, "The command file '%s' is not in any valid format.", szFile);
  166.     PrintWarning(szLine);
  167.     return fFalse;
  168.   }
  169.  
  170.   while(!feof(file))
  171.   {
  172.     while(!feof(file) && (ch = getc(file)) < ' ')
  173.       ;
  174.     for(szLine[0] = ch, i = 1; i < cchSzMax && !feof(file) && (szLine[i] = getc(file)) >= ' '; i++)
  175.       ;
  176.     szLine[i] = chNull;
  177.     argc= NParseCommandLine(szLine, argv);
  178.  
  179.     if (!FProcessSwitches(argc, argv))
  180.       return fFalse;
  181.   }
  182.  
  183.   return fTrue;
  184. }
  185.  
  186.  
  187. /* Take the current chart information, and write it out to the file   */
  188. /* as indicated by the -o switch. This is only executed at the end of */
  189. /* program execution if the -o switch is in effect.                   */
  190.  
  191. bool FOutputData()
  192. {
  193.   char sz[cchSzDef];
  194.   FILE *file;
  195.   int i, j;
  196.   real rT;
  197.  
  198.   file = fopen(is.szFileOut, "w");  /* Create and open the file for output. */
  199.  
  200.   if (file == NULL)
  201.   {
  202.     sprintf(sz, "File %s can not be created.", is.szFileOut);
  203.     PrintError(sz);
  204.     return fFalse;
  205.   }
  206.  
  207.   if (!us.fWritePos) 
  208.   {
  209.     /* Write the chart information to the file. */
  210.  
  211.     if (Mon < 1) 
  212.     {
  213.       fclose(file);
  214.       PrintError("Can't output chart with no time/space to file.");
  215.       return fFalse;
  216.     }
  217.  
  218.     if (us.fWriteOld) 
  219.     {
  220.       fprintf(file, "%d\n%d\n%d\n%.2f\n%.2f\n%.2f\n%.2f\n",
  221.         Mon, Day, Yea, Tim, Zon-Dst, Lon, Lat);
  222.     } 
  223.  
  224.     else 
  225.     {
  226.       fprintf(file, "@0102  ; %s chart info.\n", szAppName);
  227.       i = us.fAnsi;
  228.       us.fAnsi = fFalse;
  229.  
  230.       fprintf(file, "%cqb %c%c%c %d %d %s %s %s %s\n", chSwitch, chMon3(Mon),
  231.         Day, Yea, SzTim(Tim), Dst == 0.0 ? "ST" : (Dst == 1.0 ? "DT" :
  232.         SzZone(Dst)), SzZone(-Zon), SzLocation(Lon, Lat));
  233.  
  234.       fprintf(file, "%czi \"%s\" \"%s\"\n", chSwitch, ciMain.nam, ciMain.loc);
  235.       us.fAnsi = i;
  236.     }
  237.   } else {
  238.  
  239.     /* However, if the -o0 switch is in effect, then write the actual */
  240.     /* positions of the planets and houses to the file instead.       */
  241.  
  242.     if (us.fWriteOld) 
  243.     {
  244.       for (i = 1; i <= oNorm; i++) 
  245.       {
  246.         j = (int)planet[i];
  247.         fprintf(file, "%c%c%c: %2d %2d %10.7f\n", chObj3(i),
  248.           j%30, j/30+1, RFract(planet[i])*60.0);              /* Position */
  249.         rT = planetalt[i];
  250.         fprintf(file, "[%c]: %3d %12.8f\n",                   /* Altitude */
  251.           ret[i] >= 0.0 ? 'D' : chRet, (int)(RSgn(rT)*
  252.           RFloor(RAbs(rT))), (rT-(real)(int)rT)*60.0);     /* Retrograde? */
  253.         if (i == oNod)
  254.           i = oFor-1;
  255.         else if (i == oFor)
  256.           i = oMC -1;
  257.         else if (i == oMC)
  258.           i = oAsc-1;
  259.         else if (i == oAsc)
  260.           i = oVtx-1;
  261.         else if (i == oVtx)    /* Skip minor cusps to write uranians  */
  262.           i = us.fUranian ? uranLo-1 : cObj;
  263.       }
  264.  
  265.       for (i = 1; i <= cSign/2; i++)   /* Write first six cusp positions */
  266.       {
  267.         j = (int)house[i];
  268.         fprintf(file, "H_%c: %2d %2d %10.7f\n",
  269.           'a'+i-1, j%30, j/30+1, RFract(house[i])*60.0);
  270.       }
  271.  
  272.     } 
  273.  
  274.     else /* !us.fWriteOld */
  275.     {
  276.       fprintf(file, "@0203  ; %s chart positions.\n", szAppName);
  277.  
  278.       for (i = 1; i <= cObj; i++) if (!ignore[i] || FCusp(i))
  279.       {
  280.         fprintf(file, "%cYF ", chSwitch);
  281.         if (i <= oNorm)
  282.           fprintf(file, "%c%c%c", chObj3(i));
  283.         else
  284.           fprintf(file, "%3d", i);
  285.         rT = FBetween(i, cuspLo-1+4, cuspLo-1+9) ? house[i-(cuspLo-1)] : planet[i];
  286.         j = (int)rT;
  287.  
  288.         fprintf(file, ":%3d %c%c%c%13.9f,%4d%13.9f,",
  289.           j%30, chSig3(j/30+1), RFract(rT)*60.0,
  290.           (int)planetalt[i], RFract(RAbs(planetalt[i]))*60.0);
  291.  
  292.         rT = i > oNorm ? 999.0 : (i == oMoo && !us.fPlacalc ? 0.0026 :
  293.           RSqr(spacex[i]*spacex[i]+spacey[i]*spacey[i]+spacez[i]*spacez[i]));
  294.  
  295.         fprintf(file, "%14.9f%14.9f\n", DFromR(ret[i]), rT);
  296.       }
  297.     }
  298.   }
  299.  
  300.   /* Now write any extra strings that were on the command line after the -o */
  301.   /* specification but before the next switch, to the file as comments.     */
  302.  
  303.   for (i = 1; i < is.cszComment; i++) 
  304.   {
  305.     is.rgszComment++;
  306.     fprintf(file, "%s%s\n", us.fWriteOld ? "" : "; ", is.rgszComment[1]);
  307.   }
  308.   fclose(file);
  309.   return fTrue;
  310. }
  311.  
  312.  
  313. /*
  314. ******************************************************************************
  315. ** User Input Routines.
  316. ******************************************************************************
  317. */
  318.  
  319. /* Given a string, return an index number corresponding to what the string */
  320. /* indicates, based on a given parsing mode. In most cases this is mainly  */
  321. /* looking up a string in the appropriate array and returning the index.   */
  322.  
  323. int NParseSz(szEntry, pm)
  324. char *szEntry;
  325. int pm;
  326. {
  327.   char szLocal[cchSzMax], *sz, ch0, ch1, ch2;
  328.   int cch, n, i;
  329.  
  330.   /* First strip off any leading or trailing spaces. */
  331.   for (cch = 0; (szLocal[cch] = szEntry[cch]); cch++)
  332.     ;
  333.  
  334.   while (cch && szLocal[cch-1] <= ' ')
  335.     szLocal[--cch] = chNull;
  336.  
  337.   for (sz = szLocal; *sz && *sz <= ' '; sz++, cch--)
  338.     ;
  339.  
  340.   if (cch >= 3) 
  341.   {
  342.     ch0 = ChCap(sz[0]); ch1 = ChUncap(sz[1]); ch2 = ChUncap(sz[2]);
  343.     switch (pm) {
  344.  
  345.     /* Parse months, e.g. "February" or "Feb" -> 2 for February. */
  346.  
  347.     case pmMon:
  348.       for (i = 1; i <= cSign; i++) {
  349.         if (ch0 == szMonth[i][0] && ch1 == szMonth[i][1] && ch2 == szMonth[i][2])
  350.           return i;
  351.       }
  352.       break;
  353.  
  354.     /* Parse planets, e.g. "Jupiter" or "Jup" -> 6 for Jupiter. */
  355.  
  356.     case pmObject:
  357.       for (i = 1; i <= cObj; i++) 
  358.       {
  359.         if (ch0 == szObjName[i][0] && ch1 == szObjName[i][1] && ch2 == szObjName[i][2])
  360.           return i;
  361.       }
  362.       if (ch0 == 'L' && ch1 == 'i' && ch2 == 'l')
  363.         return oLil;
  364.       if (ch0 == 'S' && ch1 == '.' && ch2 == 'n')
  365.         return oSou;
  366.       break;
  367.  
  368.     /* Parse aspects, e.g. "Conjunct" or "Con" -> 1 for the Conjunction. */
  369.  
  370.     case pmAspect:
  371.       for (i = 1; i <= cAspect; i++) 
  372.       {
  373.         if (ch0 == szAspectAbbrev[i][0] &&
  374.             ch1 == ChUncap(szAspectAbbrev[i][1]) &&
  375.             ch2 == szAspectAbbrev[i][2])
  376.           return i;
  377.       }
  378.       break;
  379.  
  380.     /* Parse house systems, e.g. "Koch" or "Koc" -> 1 for Koch houses. */
  381.  
  382.     case pmSystem:
  383.       for (i = 1; i <= cSystem; i++) 
  384.       {
  385.         if (ch0 == szSystem[i][0] && ch1 == szSystem[i][1] && ch2 == szSystem[i][2])
  386.           return i;
  387.       }
  388.  
  389.     /* Parse zodiac signs, e.g. "Scorpio" or "Sco" -> 8 for Scorpio. */
  390.  
  391.     case pmSign:
  392.       for (i = 1; i <= cSign; i++) 
  393.       {
  394.         if (ch0 == szSignName[i][0] && ch1 == szSignName[i][1] && ch2 == szSignName[i][2])
  395.           return i;
  396.       }
  397.  
  398.     /* Parse colors, e.g. "White" or "Whi" -> 15 for White. */
  399.  
  400.     case pmColor:
  401.       for (i = 0; i < 16 ; i++) 
  402.       {
  403.         if (ch0 == szColor[i][0] && ch1 == szColor[i][1] && ch2 == ChUncap(szColor[i][2]))
  404.           return i;
  405.       }
  406.     }
  407.   }
  408.   n = atoi(sz);
  409.  
  410.   if (pm == pmYea) 
  411.   {
  412.     /* For years, process any "BC" (or "B.C.", "b.c", and variations) and   */
  413.     /* convert an example such as "5BC" to -4. For negative years, note the */
  414.     /* difference of one, as 1AD was preceeded by 1BC, with no year zero.   */
  415.  
  416.     i = Max(cch-1, 0);
  417.     if (i && sz[i] == '.')
  418.       i--;
  419.     if (i && ChCap(sz[i]) == 'C')
  420.       i--;
  421.     if (i && sz[i] == '.')
  422.       i--;
  423.     if (i && ChCap(sz[i]) == 'B')
  424.       n = 1 - n;
  425.   }
  426.   return n;
  427. }
  428.  
  429.  
  430. /* Given a string, return a floating point number corresponding to what the  */
  431. /* string indicates, based on a given parsing mode, like above for integers. */
  432.  
  433. real RParseSz(szEntry, pm)
  434. char *szEntry;
  435. int pm;
  436. {
  437.   char szLocal[cchSzMax], *sz, *pch, ch;
  438.   int cch, i, f = fFalse;
  439.   real r;
  440.  
  441.   /* First strip off any leading or trailing spaces. */
  442.  
  443.   for (cch = 0; (szLocal[cch] = szEntry[cch]); cch++)
  444.     ;
  445.  
  446.   while (cch && szLocal[cch-1] <= ' ')
  447.     szLocal[--cch] = chNull;
  448.  
  449.   for (sz = szLocal; *sz && *sz <= ' '; sz++, cch--);
  450.     ;
  451.  
  452.   /* Capitalize all letters and make colons be periods to be like numbers. */
  453.  
  454.   for (pch = sz; *pch; pch++) 
  455.   {
  456.     ch = *pch;
  457.     if (ch == ':')
  458.       ch = '.';
  459.     else
  460.       ch = ChCap(ch);
  461.     *pch = ch;
  462.   }
  463.   ch = sz[0];
  464.  
  465.   if (pm == pmTim) 
  466.   {
  467.     /* For times, process "Noon" and "Midnight" (or just "N" and "M"). */
  468.  
  469.     if (ch == 'N')
  470.       return 12.0;
  471.     else if (ch == 'M')
  472.       return 0.0;
  473.  
  474.   } 
  475.  
  476.   else if (pm == pmDst)
  477.   {
  478.     /* For the Daylight time flag, "Daylight", "Yes", and "True" (or just */
  479.     /* their first characters) are all indications to be ahead one hour.  */
  480.  
  481.     if (ch == 'D' || ch == 'Y' || ch == 'T')
  482.       return 1.0;
  483.  
  484.     /* "Standard", "No", and "False" mean the normal zero offset. */
  485.  
  486.     else if (ch == 'S' || ch == 'N' || ch == 'F')
  487.       return 0.0;
  488.  
  489.   } 
  490.  
  491.   else if (pm == pmZon) 
  492.   {
  493.  
  494.     /* For time zones, see if the abbrev is in a table, e.g. "EST" -> 5. */
  495.  
  496.     for (i = 0; i < cZone; i++)
  497.       if (NCompareSz(sz, szZon[i]) == 0)
  498.         return rZon[i];
  499.  
  500.   } 
  501.  
  502.   else if (pm == pmLon || pm == pmLat) 
  503.   {
  504.     /* For locations, negate the value for an "E" or "S" in the middle    */
  505.     /* somewhere (e.g. "105E30" or "27:40S") for eastern/southern values. */
  506.  
  507.     for (i = 0; i < cch; i++) 
  508.     {
  509.       ch = sz[i];
  510.       if (FCapCh(ch)) 
  511.       {
  512.         if (ch == 'E' || ch == 'S')
  513.           f = fTrue;
  514.         sz[i] = '.';
  515.         i = cch;
  516.       }
  517.     }
  518.     ch = sz[0];
  519.   }
  520.  
  521.   /* Anything still at this point should be in a numeric format. */
  522.  
  523.   if (!FNumCh(ch) && ch != '+' && ch != '-' && ch != '.')
  524.     return rLarge;
  525.  
  526.   r = (f ? -1.0 : 1.0) * atof(sz);
  527.  
  528.   if (pm == pmTim) 
  529.   {
  530.     /* Backtrack over any time suffix, i.e. "AM", "p.m." and variations. */
  531.  
  532.     i = Max(cch-1, 0);
  533.     if (i && sz[i] == '.')
  534.       i--;
  535.     if (i && sz[i] == 'M')
  536.       i--;
  537.     if (i && sz[i] == '.')
  538.       i--;
  539.     if (i) 
  540.     {
  541.       ch = sz[i];
  542.       if (ch == 'A')                   /* Adjust value appropriately */
  543.         r = r >= 12.0 ? r-12.0 : r;    /* if AM or PM suffix.        */
  544.       else if (ch == 'P')
  545.         r = r >= 12.0 ? r : r+12.0;
  546.     }
  547.   }
  548.   return r;
  549. }
  550.  
  551.  
  552. /* Stop and wait for the user to enter a line of text given a prompt to */
  553. /* display and a string buffer to fill with it.                         */
  554.  
  555. void InputString(szPrompt, sz)
  556. char *szPrompt, *sz;
  557. {
  558.   FILE *file;
  559.  
  560.   file = S; S = stdout;
  561.   PrintSz(szPrompt);
  562.   AnsiColor(kYellow);
  563.   PrintSz(" > ");
  564.   AnsiColor(kDefault);
  565.  
  566. #ifdef AMIGA
  567.   if(gi.win)
  568.     AmigaGetString(sz);
  569.   else
  570. #endif /* AMIGA */
  571.  
  572.   if (gets(sz) == NULL)    /* Pressing control-D will terminate the */
  573.     Terminate(tcForce);    /* program (at least on some machines.)  */
  574.  
  575.   S = file;
  576.   is.cchCol = 0;
  577. }
  578.  
  579.  
  580. /* Prompt the user for a floating point value, parsing as appropriate, and */
  581. /* make sure it conforms to the specified bounds before returning it.      */
  582.  
  583. int NInputRange(szPrompt, low, high, pm)
  584. char *szPrompt;
  585. int low, high;
  586. int pm;
  587. {
  588.   char szLine[cchSzDef];
  589.   int n;
  590.  
  591.   loop 
  592.   {
  593.     InputString(szPrompt, szLine);
  594.     n = NParseSz(szLine, pm);
  595.     if (FBetween(n, low, high))
  596.       return n;
  597.     sprintf(szLine, "Value %d out of range from %d to %d.", n, low, high);
  598.     PrintWarning(szLine);
  599.   }
  600. }
  601.  
  602.  
  603. /* This is identical to above except it takes/returns floating point values. */
  604.  
  605. real RInputRange(szPrompt, low, high, pm)
  606. char *szPrompt;
  607. real low, high;
  608. int pm;
  609. {
  610.   char szLine[cchSzDef];
  611.   real r;
  612.  
  613.   loop 
  614.   {
  615.     InputString(szPrompt, szLine);
  616.     r = RParseSz(szLine, pm);
  617.     if (FBetween(r, low, high))
  618.       return r;
  619.     sprintf(szLine, "Value %.0f out of range from %.0f to %.0f.", r, low, high);
  620.     PrintWarning(szLine);
  621.   }
  622. }
  623.  
  624.  
  625. /* This important procedure gets all the parameters defining the chart that  */
  626. /* will be worked with later. Given a "filename", it gets from it all the    */
  627. /* pertinent chart information. This is more than just reading from a file - */
  628. /* the procedure also takes care of the cases of prompting the user for the  */
  629. /* information and using the time functions to determine the date now - the  */
  630. /* program considers these cases "virtual" files. Furthermore, when reading  */
  631. /* from a real file, we have to check if it was written in the -o0 format.   */
  632.  
  633. bool FInputData(szFile)
  634. char *szFile;
  635. {
  636.   FILE *file;
  637.   char sz[cchSzDef], ch;
  638.   int i, fT;
  639.   real k, l, m;
  640.  
  641.   /* If we are to read from the virtual file "nul" that means to leave the */
  642.   /* chart information alone with whatever settings it may have already.   */
  643.  
  644.   if (NCompareSz(szFile, szNulCore) == 0)
  645.   {
  646.     is.fHaveInfo = fTrue;
  647.     return fTrue;
  648.   }
  649.  
  650.   /* If we are to read from the virtual file "set" then that means use a   */
  651.   /* particular set of chart information generated earlier in the program. */
  652.  
  653.   if (NCompareSz(szFile, szSetCore) == 0) 
  654.   {
  655.     is.fHaveInfo = fTrue;
  656.     ciCore = ciSave;
  657.     return fTrue;
  658.   }
  659.  
  660. #ifdef TIME
  661.   /* If we are to read from the file "now" then that means use the time */
  662.   /* functions to calculate the present date and time.                  */
  663.  
  664.   if (NCompareSz(szFile, szNowCore) == 0)
  665.   {
  666.     is.fHaveInfo = fTrue;
  667.     SS = us.dstDef; ZZ = us.zonDef; OO = us.lonDef; AA = us.latDef;
  668.     GetTimeNow(&MM, &DD, &YY, &TT, ZZ-SS);
  669.     return fTrue;
  670.   }
  671. #endif
  672.  
  673.   /* If we are to read from the file "tty" then that means prompt the user */
  674.   /* for all the chart information.                                        */
  675.  
  676.   if (NCompareSz(szFile, szTtyCore) == 0)
  677.   {
  678.     file = S; S = stdout;
  679.   
  680.     if (!us.fNoSwitches)
  681.     {
  682.       /* Temporarily disable an internal redirection of output to a file  */
  683.       /* because we always want user headers and prompts to be displayed. */
  684.  
  685.       AnsiColor(kWhite);
  686.       sprintf(sz, "** %s version %s ", szAppName, szVersionCore); PrintSz(sz);
  687.       sprintf(sz, "(See '%cHc' switch for copyrights and credits.) **\n", chSwitch); PrintSz(sz);
  688.       AnsiColor(kDefault);
  689.       sprintf(sz, "   Invoke as '%s %cH' for list of command line options.\n",
  690.         ProcessProgname(is.szProgName), chSwitch); PrintSz(sz);
  691.     }
  692.  
  693.     MM = NInputRange("Enter month for chart (e.g. '8' 'Aug')", 1, 12, pmMon);
  694.     DD = NInputRange("Enter day   for chart (e.g. '1' '31') ", 1, DayInMonth(MM, 0), pmDay);
  695.     YY = NInputRange("Enter year  for chart (e.g. '1995')   ", -5000, 5000, pmYea);
  696.  
  697.     if (FBetween(YY, 0, 99)) 
  698.     {
  699.       sprintf(sz,"Assuming first century A.D. is really meant instead of %d.", 1900 + YY);
  700.       PrintWarning(sz);
  701.     }
  702.     TT = RInputRange("Enter time  for chart (e.g. '18:30' '6:30pm')  ", -2.0, 24.0, pmTim);
  703.  
  704.     SS = us.fWriteOld ? 0.0 : RInputRange("Enter if Daylight time in effect (e.g. 'y' '1')", -24.0, 24.0, pmDst);
  705.     ZZ = RInputRange("Enter time zone (e.g. '5' 'ET' for Eastern)    ", -24.0, 24.0, pmZon);
  706.  
  707.     if ((int)(RFract(ZZ) * 100.0 + rRound) == 50)
  708.     {
  709.       PrintWarning("Assuming unusual zone of 50 minutes after the hour instead of 30.");
  710.     }
  711.  
  712.     OO = RInputRange("Enter Longitude of place (e.g. '122W20')", -rDegHalf, rDegHalf, pmLon);
  713.     AA = RInputRange("Enter Latitude  of place (e.g. '47N36') ", -rDegQuad, rDegQuad, pmLat);
  714.  
  715.     if (!us.fWriteOld) 
  716.     {
  717.       InputString("Enter name or title for chart ", sz);
  718.       ciCore.nam = SzPersist(sz);
  719.       InputString("Enter name of city or location", sz);
  720.       ciCore.loc = SzPersist(sz);
  721.     }
  722.     PrintL();
  723.     is.cchRow = 0;
  724.     S = file;
  725.     return fTrue;
  726.   }
  727.  
  728.   /* Now that the special cases are taken care of, we can assume we are */
  729.   /* to read from a real file.                                          */
  730.  
  731.   file = FileOpen(szFile, 1);
  732.   if (file == NULL)
  733.     return fFalse;
  734.   is.fHaveInfo = fTrue;
  735.   ch = getc(file); ungetc(ch, file);
  736.  
  737.   /* Read the chart parameters from a standard command switch file. */
  738.  
  739.   if (ch == '@') 
  740.   {
  741.     fT = is.fSzPersist; is.fSzPersist = fFalse;
  742.     if (!FProcessSwitchFile(szFile, file))
  743.       return fFalse;
  744.     is.fSzPersist = fT;
  745.   }
  746.  
  747.   /* Read the chart info from an older style -o list of seven numbers. */
  748.  
  749.   else if (FNumCh(ch))
  750.   {
  751.     SS = 0.0;
  752.     fscanf(file, "%d%d%d", &MM, &DD, &YY);
  753.     fscanf(file, "%lf%lf%lf%lf", &TT, &ZZ, &OO, &AA);
  754.  
  755.     if (!FValidMon(MM) || !FValidDay(DD, MM, YY) || !FValidYea(YY) ||
  756.         !FValidTim(TT) || !FValidZon(ZZ) || !FValidLon(OO) || !FValidLat(AA))
  757.     {
  758.       PrintWarning("Values in old style chart info file are out of range.");
  759.       return fFalse;
  760.     }
  761.   }
  762.  
  763.   /* Read the actual chart positions from a file produced with the -o0. */
  764.  
  765.   else if (ch == 'S')
  766.   {
  767.     MM = -1;
  768.  
  769.     /* Hack: A negative month value means the chart parameters are invalid, */
  770.     /* hence -o0 is in effect and we can assume the chart positions are     */
  771.     /* already in memory so we don't have to calculate them later.          */
  772.  
  773.     for (i = 1; i <= oNorm; i++) 
  774.     {
  775.       fscanf(file, "%s%lf%lf%lf", sz, &k, &l, &m);
  776.       planet[i] = Mod((l-1.0)*30.0+k+m/60.0);
  777.       fscanf(file, "%s%lf%lf", sz, &k, &l);
  778.       if ((m = k+l/60.0) > rDegHalf)
  779.         m = rDegMax - m;
  780.       planetalt[i] = m;
  781.       ret[i] = RFromD(sz[1] == 'D' ? 1.0 : -1.0);
  782.  
  783.       /* -o0 files from versions 3.05 and before don't have the uranians in  */
  784.       /* them. Be prepared to skip over them in old files for compatibility. */
  785.  
  786.       if (i == oVtx) 
  787.       {
  788.         while (getc(file) >= ' ')
  789.           ;
  790.         if ((ch = getc(file)) != 'H')
  791.           i = cuspHi;
  792.         else
  793.           i = cObj;
  794.       }
  795.       if (i == oNod)
  796.         i = oFor-1;
  797.       else if (i == oFor)
  798.         i = oLil-1;
  799.       else if (i == oLil)
  800.         i = oEP -1;
  801.       else if (i == oEP)
  802.         i = oVtx-1;
  803.     }
  804.  
  805.     for (i = 1; i <= cSign/2; i++)
  806.     {
  807.       fscanf(file, "%s%lf%lf%lf", sz, &k, &l, &m);
  808.       house[i+6] = Mod((house[i] = Mod((l-1.0)*30.0+k+m/60.0))+rDegHalf);
  809.     }
  810.  
  811.     for (i = 1; i <= cSign; i++)
  812.       planet[cuspLo-1+i] = house[i];
  813.  
  814.     planet[oMC] = planet[oLil]; planet[oNad] = Mod(planet[oMC]  + rDegHalf);
  815.     planet[oAsc] = planet[oEP]; planet[oDes] = Mod(planet[oAsc] + rDegHalf);
  816.     planet[oSou] = Mod(planet[oNod] + rDegHalf); ret[oSou] = ret[oNod];
  817.   }
  818.  
  819.   else
  820.   {
  821.     PrintWarning("The chart info file is not in any valid format.");
  822.     return fFalse;
  823.   }
  824.  
  825.   fclose(file);
  826.   return fTrue;
  827. }
  828.  
  829. /* io.c */
  830.